const util = require('../../utils/util.js')
Page({
  data: {
    ver: null,
    deviceId: '',
    name: '',
    connected: false,
    chipType: null,
    currentImage: null,
    imageMaxSixe: null,
    blockSixe: '',
    startAddress: '',
    newImage: null,
    canWrite: false,
    percent: 0,
    outLogs: [],
    fileName: '',
    fileType: '',
    filePath: '',
    fileSize: 0,
    showSetting: true,
    sendAarryBuffer: '',
    sendCommand: false,
    sendFileFirst: false,
    sendFileSecond: false,
    sendEndCmd: false,
    hadSendLength: 0,
    updateFlag: false,
    num: 0,
    ext: '',
    checkNum: ''
  },
  onShow() {
    wx.getStorage({
      key: 'token',
      fail: (err) => {
        wx.navigateTo({
          url: '/pages/login/login',
        })
      }
    })
  },
  onLoad: function (options) {
    this.setData({
      deviceId: options.deviceId,
      name: options.name,
      connected: true,
      updateFlag: false,
      filePath: JSON.parse(wx.getStorageSync('Hex')).path,
      fileName: JSON.parse(wx.getStorageSync('Hex')).name,
      fileSize: JSON.parse(wx.getStorageSync('Hex')).size
    })
    if (options.deviceId) {
      //根据deviceId获取服务
      this.getBLEDeviceServices(options.deviceId)
    }
  },
  onUnload() {
    clearTimeout()
    this.closeBLEConnection()
  },
  // 创建连接
  createBLEConnection() {
    this.setData({
      sendEndCmd: false,
      sendCommand: false,
      sendFileFirst: false,
      sendFileSecond: false,
      updateFlag: false,
      hadSendLength: 0,
      percent: 0
    })
    const deviceId = this.data.deviceId
    wx.showLoading({
      title: '正在连接...',
    })
    this.logText('连接中...')
    wx.createBLEConnection({
      deviceId,
      success: (res) => {
        this.getBLEDeviceServices(this.data.deviceId)
        wx.hideLoading()
        this.setData({
          connected: true,
        })
        wx.showToast({
          title: '连接成功',
          icon: 'success',
          duration: 1000
        })
      },
      fail(err) {
        console.log(err);
        wx.hideLoading()
        wx.showToast({
          title: '连接失败',
          icon: 'none',
          duration: 2000
        })
      }
    })
  },
  // 6.获取蓝牙服务
  getBLEDeviceServices(deviceId) {
    wx.getBLEDeviceServices({
      deviceId,
      success: (res) => {
        console.log('蓝牙服务', res);
        for (let i = 0; i < res.services.length; i++) {
          if (res.services[i].uuid.indexOf('FFE0') > 0) {
            this.logText(`${this.data.name}已连接`, true)
            this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
            return
          }
        }
      }
    })
  },
  // 7.获取蓝牙设备某个服务中所有特征值
  getBLEDeviceCharacteristics(deviceId, serviceId) {
    wx.getBLEDeviceCharacteristics({
      deviceId,
      serviceId,
      success: (res) => {
        for (let i = 0; i < res.characteristics.length; i++) {
          let item = res.characteristics[i]
          if (item.uuid.indexOf('FFE1') > 0) {
            if (item.properties.write) {
              this.setData({
                canWrite: true
              })
              this._deviceId = deviceId
              this._serviceId = serviceId
              this._characteristicId = item.uuid
            }
          }
        }
        this.getChipInfo()
      },
      fail(res) {
        console.error('getBLEDeviceCharacteristics', res)
      }
    })
    var that = this
    //开启蓝牙状态监听
    wx.onBLEConnectionStateChange(function (res) {
      if (!res.connected) {
        wx.showToast({
          title: '蓝牙连接已断开',
          icon: 'none',
          duration: 2000,
        })
        if (that.data.sendEndCmd) {
          that.logText('升级成功！')
          that.setData({
            num: 0
          })
          wx.hideLoading()
          wx.showToast({
            title: '升级成功!',
            icon: 'success'
          })
        }
        if (that.data.connected) {
          that.closeBLEConnection()
          that.setData({
            connected: false,
            updateFlag: false
          })
        }
      }
    });
    // 操作之前先监听，保证第一时间获取数据
    wx.onBLECharacteristicValueChange(function (res) {
      let receive = ab2hex(res.value)
      console.log('读取数据', receive);
      //根据接收到数据的首字节进行对应操作
      if (receive.slice(0, 2) == '00') {
        //发送擦除指令收到回复后处理
        if (that.data.sendCommand) {
          that.logText('擦除成功！')
          wx.hideLoading()
          wx.showLoading({
            title: '开始下发文件',
          })
          that.logText('开始下发文件...')
          setTimeout(() => {
            that.startSendFile()
          }, 1000);
          that.setData({
            sendCommand: false
          })
          //发送升级文件成功收到回复后处理
        } else if (that.data.sendFileFirst) {
          wx.hideLoading()
          wx.showLoading({
            title: '开始文件校验',
          })
          that.logText('开始下发校验文件...')
          that.sendFileAngin()
          that.setData({
            sendFileFirst: false
          })
          //发送校验文件成功收到回复后处理
        } else if (that.data.sendFileSecond) {
          wx.hideLoading()
          wx.showToast({
            title: '校验成功',
            icon: 'success',
            duration: 2000
          })
          that.logText('文件校验成功！')
          that.sendEndCommod()
          that.setData({
            sendFileSecond: false
          })
        }
        //发送读取硬件信息，收到回复后处理
      } else if (receive.slice(0, 2) == '01' || receive.slice(0, 2) == '02') {
        if (receive.slice(0, 2) == '01') {
          that.setData({
            currentImage: 'A'
          })
        } else {
          that.setData({
            currentImage: 'B'
          })
        }
        if (receive.slice(14, 16) == '83') {
          that.setData({
            chipType: 'CH583'
          })
        } else if (receive.slice(14, 16) == '92') {
          that.setData({
            chipType: 'CH592'
          })
        } else if (receive.slice(14, 16) == '73') {
          that.setData({
            chipType: 'CH573'
          })
        } else {
          wx.showToast({
            title: '芯片类型不匹配!',
            icon: 'none'
          })
        }
        let result = "";
        let hexString = receive.slice((receive.length - 22), (receive.length - 2))
        for (let i = 0; i < hexString.length; i += 2) {
          let hex = hexString.substr(i, 2);
          let charCode = parseInt(hex, 16);
          let char = String.fromCharCode(charCode);
          result += char;
        }
        that.setData({
          ver: result,
          blockSixe: that.small2Hex(receive.slice(10, 14)),
          startAddress: that.small2Hex(receive.slice(6, 10)) + that.small2Hex(receive.slice(2, 6)),
          imageMaxSixe: parseInt(that.small2Hex(receive.slice(6, 10)) + that.small2Hex(receive.slice(2, 6)), 16)
        })
        that.logText('获取芯片信息成功！')
      } else if (receive.slice(0, 2).toUpperCase() == 'FE') {
        wx.hideLoading()
        that.logText('升级失败!')
        wx.showToast({
          title: '升级失败',
          icon: 'none',
          image: '/image/warning.png'
        })
        that.closeBLEConnection()
      }
    })
  },
  //发送buffer到蓝牙的方法
  handleSendvalue(buffer, flag, deviceId, serviceId, characteristicId) {
    let that = this
    wx.writeBLECharacteristicValue({
      deviceId: deviceId,
      serviceId: serviceId,
      characteristicId: characteristicId,
      value: buffer,
      success: function (res) {
        if (flag == 1) { //读取芯片信息
          setTimeout(() => {
            wx.hideLoading()
            wx.readBLECharacteristicValue({
              deviceId,
              serviceId,
              characteristicId,
            })
          }, 2500);
        } else if (flag == 2) { //发送擦除指令
          wx.showLoading({
            title: '擦除中...',
          })
          that.setData({
            sendCommand: true
          })
          setTimeout(() => {
            wx.readBLECharacteristicValue({
              deviceId,
              serviceId,
              characteristicId,
            })
          }, 2500);
        } else if (flag == 3) { //发送文件
          if (that.data.hadSendLength >= that.data.sendAarryBuffer.byteLength) {
            that.setData({
              sendFileFirst: true,
              hadSendLength: 0,
              percent: 100,
            })
            wx.readBLECharacteristicValue({
              deviceId,
              serviceId,
              characteristicId,
            })
          } else {
            that.startSendFile()
            that.setData({
              percent: ((that.data.hadSendLength / that.data.sendAarryBuffer.byteLength) * 100).toFixed(0)
            })
          }
        } else if (flag == 4) { //发送检验文件
          setTimeout(() => {
            that.setData({
              sendFileSecond: true,
            })
            wx.readBLECharacteristicValue({
              deviceId,
              serviceId,
              characteristicId,
            })
          }, 2500);
        } else if (flag == 5) { //发送结束命令
          that.setData({
            sendEndCmd: true
          })
          wx.readBLECharacteristicValue({
            deviceId,
            serviceId,
            characteristicId,
          })
        }
      },
      fail: function (res) {
        that.logText('发送失败!')
        that.setData({
          percent: 0
        })
        that.closeBLEConnection()
        wx.showToast({
          title: '发送失败',
          icon: "none",
          duration: 1000
        })
      }
    })
  },
  //读取芯片信息按钮点击事件
  getChipInfo() {
    if (this.data.updateFlag || !this.data.connected) {
      return
    }
    wx.showLoading({
      title: '获取中...',
    })
    this.logText('获取芯片信息...')
    //读取硬件信息指令封包
    let buffer = new ArrayBuffer(20)
    let dataView = new DataView(buffer)
    dataView.setUint8(0, 0x84)
    dataView.setUint8(1, 0x12)
    for (let i = 2; i < 20; i++) {
      dataView.setUint8(i, 0x00)
    }
    console.log('buffer', ab2hex(buffer));
    this.handleSendvalue(buffer, 1, this._deviceId, this._serviceId, this._characteristicId)
  },
  //选择文件按钮点击事件
  getUpdataFile(e) {
    if (this.data.updateFlag) {
      return
    }
    let that = this
    if (e.target.dataset.type !== this.data.currentImage) {
      wx.chooseMessageFile({
        count: 1,
        type: 'file',
        extension: ['.hex', 'hex'], //此处限制文件类型
        success(res) {
          wx.showLoading({
            title: '加载中...'
          })
          wx.uploadFile({
            // url: 'http://192.168.8.241:18081/tenant/product/convert', // 开发者服务器接口地址
            url: 'https://gysys.ori-dxe.com/api/tenant/product/convert', // 开发者服务器接口地址
            filePath: res.tempFiles[0].path, // 要上传文件资源的路径
            name: 'file', // 文件对应的 key
            success: uploadResult => {
              wx.downloadFile({
                url: JSON.parse(uploadResult.data).data,
                success: (e) => {
                  wx.setStorage({
                    key: 'Hex',
                    data: JSON.stringify(res.tempFiles[0]),
                    success: () => {
                      wx.hideLoading()
                      wx.setStorage({
                        key: 'Hex2',
                        data: e.tempFilePath,
                      })
                      that.setData({
                        "fileName": res.tempFiles[0].name,
                        "filePath": res.tempFiles[0].path,
                        "fileSize": res.tempFiles[0].size
                      })
                    }
                  })
                },
                fail: (err) => {
                  wx.hideLoading()
                  wx.showToast({
                    title: '下载失败',
                    icon: 'none'
                  })
                }
              })

            },
            fail: uploadError => {
              wx.hideLoading()
              // 处理上传失败的错误
              console.error(uploadError);
              wx.showToast({
                title: '上传失败',
                icon: 'error'
              })
            }
          });
        }
      })
    }
  },
  //开始升级按钮点击事件
  startUpdate() {
    if (this.data.updateFlag || !this.data.connected) {
      return
    }
    if (this.data.chipType == '' || this.data.chipType == null) {
      wx.showToast({
        title: '请先读取芯片信息',
        icon: 'none',
        image: '/image/warning.png',
        duration: 2000
      })
    } else if (this.data.fileName == '' || this.data.fileName == null) {
      wx.showToast({
        title: '请先选择升级文件',
        icon: 'none',
        image: '/image/warning.png',
        duration: 2000
      })
    } else {
      if (this.data.chipType == 'CH573' || this.data.chipType == 'CH592' || this.data.chipType == 'CH583') {
        let ext = this.data.fileName.substr(this.data.fileName.lastIndexOf('.') + 1);
        if (ext.toUpperCase() == 'HEX' || ext.toUpperCase() == 'BIN') {
          this.startReadFile()
          this.setData({
            updateFlag: true,
            ext: ext.toUpperCase()
          })
        } else {
          wx.showToast({
            title: '文件格式错误，请重新选择',
            icon: 'none',
            image: '/image/warning.png',
            duration: 2000
          })
        }
      } else {
        wx.showToast({
          title: '暂时不支持该芯片的升级',
          icon: 'none',
          image: '/image/warning.png',
          duration: 2000
        })
      }
    }
  },
  //验证芯片型号及文件通过后，读取文件到AarryBuffer中
  startReadFile() {
    const that = this
    const fs = wx.getFileSystemManager()
    fs.readFile({
      filePath: wx.getStorageSync('Hex2'),
      success(res) {
        that.setData({
          sendAarryBuffer: str2ab(ab2hex(res.data).slice(24)),
          checkNum: ab2hex(res.data).slice(0, 24)
        })
        if (that.data.checkNum.slice(0, 8) == '4259574c') {
          that.sendEraseCommand()
        } else {
          that.closeBLEConnection(2)
          that.logText('文件不合法')
          wx.showModal({
            title: '温馨提示',
            content: '文件不合法',
            showCancel: false
          })
        }
      },
      fail(res) {
        wx.showToast({
          title: '文件读取错误',
          icon: 'none',
          duration: 2000
        });
        that.setData({
          fileName: '',
          fileSize: 0
        })
      }
    })
  },
  //发送擦除命令
  sendEraseCommand() {
    let buffer = new ArrayBuffer(20)
    let dataView = new DataView(buffer)
    dataView.setUint8(0, 0x81)
    dataView.setUint8(1, 0x00)
    //计算需要擦除块的个数（文件大小+（块大小-1））/大小
    let block = Math.ceil((this.data.sendAarryBuffer.byteLength + (parseInt(this.data.blockSixe, 16) - 1)) / parseInt(this.data.blockSixe, 16))
    block = block.toString(16)
    console.log('文件大小', this.data.sendAarryBuffer.byteLength);
    console.log('块大小', this.data.blockSixe)
    console.log('块个数', block);
    dataView.setUint8(2, 0x00)
    dataView.setUint8(3, 0x05)
    dataView.setUint8(4, '0x' + block)
    dataView.setUint8(5, '0x' + block >> 8)
    for (let i = 6; i < 20; i++) {
      dataView.setUint8(i, 0x00)
    }
    console.log('擦除指令', ab2hex(buffer));
    this.logText('开始擦除...')
    this.handleSendvalue(buffer, 2, this._deviceId, this._serviceId, this._characteristicId)
  },
  //发送升级文件
  startSendFile() {
    let dataLength
    if (this.data.chipType == 'CH583' || this.data.chipType == 'CH573') {
      dataLength = 48
      wx.setBLEMTU({
        deviceId: this._deviceId,
        mtu: 55,
      })
    } else {
      dataLength = 240
      wx.setBLEMTU({
        deviceId: this._deviceId,
        mtu: 247,
      })
    }
    let unsentLength = this.data.sendAarryBuffer.slice(this.data.hadSendLength).byteLength
    if (unsentLength < dataLength) {
      dataLength = unsentLength
    }
    let buffer = new ArrayBuffer(dataLength + 4)
    let dataView = new DataView(buffer)
    dataView.setUint8(0, 0x80)
    dataView.setUint8(1, '0x' + dataLength.toString(16))
    let sendAddr = 0
    sendAddr = ((20480 + this.data.hadSendLength) / 16).toString(16)
    if (sendAddr.length == 3) {
      sendAddr = '0' + sendAddr
    } else if (sendAddr.length == 2) {
      sendAddr = '00' + sendAddr
    } else if (sendAddr.length == 1) {
      sendAddr = '000' + sendAddr
    }
    dataView.setUint8(2, '0x' + sendAddr.slice(2))
    dataView.setUint8(3, '0x' + sendAddr.slice(0, 2))
    for (let i = 4, j = 0; i < dataLength + 4; i++, j++) {
      dataView.setUint8(
        i, '0x' + ab2hex(this.data.sendAarryBuffer.slice(this.data.hadSendLength + j, this.data.hadSendLength + j + 1))
      )
    }
    this.data.num += 1
    console.log(`升级指令${this.data.num}`, ab2hex(buffer));
    this.setData({
      hadSendLength: this.data.hadSendLength + dataLength
    })
    this.handleSendvalue(buffer, 3, this._deviceId, this._serviceId, this._characteristicId)
  },
  //校验文件，将升级文件再发送一次，命令码由80更改成85
  sendFileAngin() {
    let that = this
    let arr = that.data.checkNum.slice(8, 16).split('')
    let arr1 = that.data.checkNum.slice(16, 24).split('')
    let str = []
    let str1 = []
    // 验证字节大小
    for (let i = 0; i < arr.length; i += 2) {
      str.push(String(arr[i]) + String(arr[i + 1]))
    }
    // checkNum
    for (let i = 0; i < arr1.length; i += 2) {
      str1.push(String(arr1[i]) + String(arr1[i + 1]))
    }
    let byt = str.reverse().join('')
    if (parseInt(byt, 16) == that.data.sendAarryBuffer.byteLength) {
      let num = str1.reverse().join('')
      console.log('校验值', num);
      let buffer1 = new ArrayBuffer(9)
      let dataView1 = new DataView(buffer1)
      dataView1.setUint8(0, 0x85)
      dataView1.setUint8(1, 0x07) //长度
      dataView1.setUint8(2, 0x00) //校验地址
      dataView1.setUint8(3, 0x00) //校验地址
      dataView1.setUint8(4, '0x' + num.slice(6)) // chksum
      dataView1.setUint8(5, '0x' + num.slice(4, 6)) // chksum
      dataView1.setUint8(6, '0x' + num.slice(2, 4)) // chksum
      dataView1.setUint8(7, '0x' + num.slice(0, 2)) // chksum
      dataView1.setUint8(8, 0x00)
      console.log('校验写入', ab2hex(buffer1));
      that.handleSendvalue(buffer1, 4, that._deviceId, that._serviceId, that._characteristicId)
    } else {
      that.closeBLEConnection(2)
      that.logText('校验失败')
      wx.hideLoading()
      wx.showModal({
        title: '温馨提示',
        content: '校验失败',
        showCancel: false
      })
    }
  },
  // 32位无符号转换
  toUnsignedInt(num) {
    return num >>>= 32; // 对于32位无符号整数
  },
  //发送结束命令
  sendEndCommod() {
    this.logText('开始升级...')
    wx.showLoading({
      title: '升级中...',
    })
    let buffer = new ArrayBuffer(20)
    let dataView = new DataView(buffer)
    dataView.setUint8(0, 0x83)
    dataView.setUint8(1, 0x12)
    for (let i = 3; i < 20; i++) {
      dataView.setUint8(i, 0x00)
    }
    console.log('发送结束命令', ab2hex(buffer));
    this.handleSendvalue(buffer, 5, this._deviceId, this._serviceId, this._characteristicId)
  },
  small2Hex(str) {
    return str.slice(2) + str.slice(0, 2)
  },
  //关闭蓝牙
  closeBLEConnection(num) {
    if (this.data.connected) {
      this.setData({
        connected: false,
        canWrite: false,
        updateFlag: false,
        hadSendLength: 0
      })
      wx.closeBLEConnection({
        deviceId: this.data.deviceId
      })
      if (num == 2) {
        wx.showToast({
          title: '连接已断开',
          icon: 'none',
          duration: 1000
        });
      }
      if (num == 1) {
        this.clearInterval()
        wx.navigateTo({
          url: '../index/index',
        })
      }
    }
  },
  // log提示
  logText(info, index) {
    let idx
    if (index) {
      idx = 0
    } else {
      idx = this.data.outLogs.length
    }
    let time = util.formatTime(new Date())
    let text = time + info
    let newItem = this.data.outLogs;
    newItem.push({
      id: idx,
      text: text
    })
    this.setData({
      outLogs: newItem
    })
  }
})
//ArrayBuffer转换成16进制
function ab2hex(buffer) {
  var hexArr = Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2))
  return hexArr.join('');
}
//hex转为字符串
function hex2a(hexx) {
  var hex = hexx.toString()
  var str = '';
  for (var i = 0; i < hex.length; i += 2)
    str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
  return str;
}
// 字符串转为ArrayBuffer对象，参数为字符串
function str2ab(str) {
  var typedArray = new Uint8Array(str.match(/[\da-f]{2}/gi).map(function (h) {
    return parseInt(h, 16)
  }))
  return typedArray.buffer
}